package com.fuchuang.seckillsystem.config;

import com.fuchuang.seckillsystem.filter.CustomAuthenticationFilter;
import com.fuchuang.seckillsystem.filter.IpRepeatRequestFilter;
import com.fuchuang.seckillsystem.filter.JwtAuthenticationFilter;
import com.fuchuang.seckillsystem.utils.JsonWebTokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.Collections;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JsonWebTokenUtils jsonWebTokenUtil;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Autowired
    private AuthenticationSuccessHandler loginSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler loginFailureHandler;

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    private IpRepeatRequestFilter ipRepeatRequestFilter;

    /**
     * @return 基于URL的跨域配置信息
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration cores = new CorsConfiguration();
        cores.setAllowCredentials(true);//允许客户端携带认证信息
        //springBoot 2.4.1版本之后，不可以用 * 号设置允许的Origin,如果不降低版本，则在跨域设置时使用setAllowedOriginPatterns方法
        // cores.setAllowedOrigins(Collections.singletonList("*"));//允许所有域名可以跨域访问
        cores.setAllowedOriginPatterns(Collections.singletonList("*"));
        cores.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "PUT", "UPDATE"));//允许哪些请求方式可以访问
        cores.setAllowedHeaders(Collections.singletonList("*"));//允许服务端访问的客户端请求头
        // 暴露哪些头部信息（因为跨域访问默认不能获取全部头部信息）
        cores.addExposedHeader(jsonWebTokenUtil.getHeader());
        // 注册跨域配置
        // 也可以使用CorsConfiguration 类的 applyPermitDefaultValues()方法使用默认配置
        source.registerCorsConfiguration("/**", cores.applyPermitDefaultValues());
        return source;
    }

    //注册自定义的UsernamePasswordAuthenticationFilter
    @Bean
    CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(loginSuccessHandler);
        filter.setAuthenticationFailureHandler(loginFailureHandler);
        filter.setFilterProcessesUrl("/login");

        //这句很关键，重用WebSecurityConfigurerAdapter配置的AuthenticationManager，不然要自己组装AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //请求失败后的处理
        http.exceptionHandling()
                //未登录异常处理
                .authenticationEntryPoint(authenticationEntryPoint)
                //登录后，权限不够异常
                .accessDeniedHandler(accessDeniedHandler);

        //请求处理
        http.authorizeRequests()
                //登录和刷新token请求无需拦截
                .antMatchers("/**")
                //.antMatchers("/login", "/user/refreshToken", "/user/register", "/excel/**")
                .permitAll()
                //其他所有请求都需要认证
                .anyRequest().authenticated()
                .and().
                formLogin().loginPage("/")
                .and()
                //自定义登出处理逻辑
                .logout().logoutSuccessHandler(logoutSuccessHandler)
                .and()
                //jwt处理，用不到session，禁用掉session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //在UsernamePasswordAuthenticationFilter之前添加token拦截器和ip拦截器,ip拦截器已修改成在拦截器中添加名单
        http.addFilterBefore(ipRepeatRequestFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);


        //允许跨域，配置后SpringSecurity会自动寻找name=corsConfigurationSource的Bean
        http.cors();
        http.csrf().disable();
    }
}
